/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bff.slimserver.musicjukebox.ui.components.radio;

import com.bff.slimserver.music.exceptions.PlaylistException;
import com.bff.slimserver.musicjukebox.lib.JukeboxProperties;
import com.bff.slimserver.musicjukebox.ui.SplashScreen;
import com.bff.bjj.utils.Utils;
import java.awt.Color;
import java.awt.Component;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.bff.slimserver.SlimPlaylist;
import org.bff.slimserver.SlimRadioPlugin;
import org.bff.slimserver.exception.SlimConnectionException;
import org.bff.slimserver.exception.SlimException;
import org.bff.slimserver.musicobjects.SlimObject;
import org.bff.slimserver.musicobjects.radio.SlimAvailableRadio;
import org.bff.slimserver.musicobjects.radio.SlimRadioItem;
 
/**
 *
 * @author bfindeisen
 */
public class RadioTree extends JTree implements TreeWillExpandListener, TreeExpansionListener {

    private SlimRadioPlugin radioPlugin;
    private SlimPlaylist playlist;
    private List<SlimAvailableRadio> radioList;
    private static DefaultMutableTreeNode top = new DefaultMutableTreeNode("Radios");
    private SplashScreen sp;
    private static List<SlimAvailableRadio> loadedList;
    private static List<SlimRadioItem> loadedItemList;

    public RadioTree() {
        super(top);

        setRowHeight(30);

        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        //setShowsRootHandles(true);

        try {
            setPlaylist(JukeboxProperties.getInstance().getPlaylist());
        } catch (PlaylistException ex) {
            Logger.getLogger(RadioTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {
            setRadioPlugin(JukeboxProperties.getInstance().getRadioPlugin());
        } catch (SlimConnectionException ex) {
            Logger.getLogger(RadioTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        setCellRenderer(new RadioTreeCellRenderer());
        //addTreeExpansionListener(this);
        //listAll();
        //addMouseListener(this);
        addTreeWillExpandListener(this);
    }

    public void listAll() throws Exception {
        top = new DefaultMutableTreeNode("Radios");

        loadedList = new ArrayList<SlimAvailableRadio>();
        loadedItemList = new ArrayList<SlimRadioItem>();
        setModel(new DefaultTreeModel(top));

        radioList = new ArrayList<SlimAvailableRadio>(getRadioPlugin().getAvailableRadios());

        for (SlimAvailableRadio radio : radioList) {
            DefaultMutableTreeNode category = new DefaultMutableTreeNode(radio);
            if (radio.isError()) {
                DefaultMutableTreeNode errorMsg = new DefaultMutableTreeNode(radio.getErrorMessage());
                category.add(errorMsg);
            } else {
                if (!radio.isSearch()) {
                    category.add(new DefaultMutableTreeNode());
                }
            }

            top.add(category);
        }
        expandRow(0);
        //setRootVisible(false);

    }

    /**
     * @return the podcaster
     */
    public SlimRadioPlugin getRadioPlugin() {
        return radioPlugin;
    }

    /**
     * @param podcaster the podcaster to set
     */
    public void setRadioPlugin(SlimRadioPlugin radioPlugin) {
        this.radioPlugin = radioPlugin;
    }

    /**
     * @return the playlist
     */
    public SlimPlaylist getPlaylist() {
        return playlist;
    }

    /**
     * @param playlist the playlist to set
     */
    public void setPlaylist(SlimPlaylist playlist) {
        this.playlist = playlist;
    }

    /**
     * @return the podcastList
     */
    public List<SlimAvailableRadio> getRadioList() {
        return radioList;
    }

    /**
     * @param podcastList the podcastList to set
     */
    public void setRadioList(List<SlimAvailableRadio> radioList) {
        this.radioList = radioList;
    }

    /**
     * @return the selectedPodcast
     */
    public SlimObject getSelectedRadio() {
        TreePath path = getSelectionPath();
        final DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
        if (node == null) //Nothing is selected.
        {
            return null;
        }

        Object nodeInfo = node.getUserObject();

        if (nodeInfo instanceof SlimRadioItem) {
            return (SlimRadioItem) nodeInfo;
        } else if (nodeInfo instanceof SlimAvailableRadio) {
            return (SlimAvailableRadio) nodeInfo;
        }

        return null;
    }

    private synchronized void loadItem(DefaultMutableTreeNode node, SlimRadioItem radioItem) {
        node.remove(0);

        ((DefaultTreeModel) getModel()).reload(node);

        List<SlimRadioItem> radioItems = new ArrayList<SlimRadioItem>();

        try {
            getRadioPlugin().loadRadio(radioItem, JukeboxProperties.getInstance().getPlayer());
            radioItems.addAll(radioItem.getRadioItems());
        } catch (SlimException ex) {
            Logger.getLogger(RadioTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        for (SlimRadioItem item : radioItems) {

            if (item.isError()) {
                DefaultMutableTreeNode errorMsg = new DefaultMutableTreeNode(item.getErrorMessage());
                node.add(errorMsg);
            } else {

                //if (!item.isAudio()) {
                if (itemHasItems(item)) {
                    DefaultMutableTreeNode itemNode = new DefaultMutableTreeNode(item);

                    node.add(itemNode);
                    itemNode.add(new DefaultMutableTreeNode());
                }
            }
        }
    }

    private synchronized void loadItem(DefaultMutableTreeNode node, SlimAvailableRadio radio) {
        node.remove(0);

        ((DefaultTreeModel) getModel()).reload(node);

        List<SlimRadioItem> radioItems = new ArrayList<SlimRadioItem>();

        try {
            SlimRadioItem sri = getRadioPlugin().loadRadio(radio, JukeboxProperties.getInstance().getPlayer());
            radioItems.addAll(sri.getRadioItems());
        } catch (SlimException ex) {
            Logger.getLogger(RadioTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        for (SlimRadioItem item : radioItems) {

            if (item.isError()) {
                DefaultMutableTreeNode errorMsg = new DefaultMutableTreeNode(item.getErrorMessage());
                node.add(errorMsg);
            } else {

                //if (!item.isAudio()) {
                if (itemHasItems(item)) {
                    DefaultMutableTreeNode itemNode = new DefaultMutableTreeNode(item);

                    node.add(itemNode);
                    itemNode.add(new DefaultMutableTreeNode());
                }
            }
        }
    }

    private boolean itemHasItems(SlimRadioItem item) {
        return !item.isAudio() && item.isContainsItems();
    }

    public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {

        TreePath path = event.getPath();

        final DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
        if (node == null) {
            return;
        }

        Object nodeInfo = node.getUserObject();

        if (nodeInfo instanceof SlimAvailableRadio) {

            final SlimAvailableRadio item = (SlimAvailableRadio) nodeInfo;

            if (!item.isSearch()) {
                boolean loaded = loadedList.contains(item);

                if (!loaded) {
                    //node.remove(0);
                    sp = new SplashScreen(Utils.getParentComponent(this), true);
                    sp.setIndeterminate(true);
                    sp.setTitleLabel("Loading Radio");
                    sp.setMainTextArea("\nLoading radio " + item.getName() + "\n\n");
                    sp.setProgressBarLabel("Loading radio...");
                    sp.pack();

                    new Thread(new Runnable() {

                        public void run() {
                            loadItem(node, item);
                            sp.setStopped(true);
                            ((DefaultTreeModel) getModel()).reload(node);
                            if (node.getChildCount() == 0) {
                                setSelectionPath(getPath(node));
                            } else {
                                expandPath(getPath(node));
                            }
                        }
                    }).start();
                    loadedList.add(item);
                }
            }
        } else if (nodeInfo instanceof SlimRadioItem) {

            final SlimRadioItem item = (SlimRadioItem) nodeInfo;

            boolean loaded = loadedItemList.contains(item);

            if (!loaded) {
                //node.remove(0);
                sp = new SplashScreen(Utils.getParentComponent(this), true);
                sp.setIndeterminate(true);
                sp.setTitleLabel("Loading Radio");
                sp.setMainTextArea("\nLoading radio " + item.getName() + "\n\n");
                sp.setProgressBarLabel("Loading radio...");
                sp.pack();

                new Thread(new Runnable() {

                    public void run() {
                        loadItem(node, item);
                        sp.setStopped(true);
                        ((DefaultTreeModel) getModel()).reload(node);
                        if (node.getChildCount() == 0) {
                            setSelectionPath(getPath(node));
                        } else {
                            expandPath(getPath(node));
                        }
                    }
                }).start();
                loadedItemList.add(item);
            }

        }


    }

    public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public TreePath getPath(TreeNode node) {
        List list = new ArrayList();

        // Add all nodes to list
        while (node != null) {
            list.add(node);
            node = node.getParent();
        }
        Collections.reverse(list);

        // Convert array of nodes to TreePath
        return new TreePath(list.toArray());
    }

    public void treeExpanded(TreeExpansionEvent event) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void treeCollapsed(TreeExpansionEvent event) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private class RadioTreeCellRenderer extends DefaultTreeCellRenderer {

        private Icon iconRoot = new ImageIcon(getClass().getResource("/resources/slimserver/radio_icon_small.jpg"));

        @Override
        public Component getTreeCellRendererComponent(JTree tree,
                Object value,
                boolean selected,
                boolean expanded,
                boolean leaf,
                int row,
                boolean hasFocus) {

            super.getTreeCellRendererComponent(
                    tree,
                    value,
                    selected,
                    expanded,
                    leaf,
                    row,
                    hasFocus);

            if (((DefaultMutableTreeNode) value).isRoot()) {
                setIcon(iconRoot);
                setText(((DefaultMutableTreeNode) value).toString());
            } else if (((DefaultMutableTreeNode) value).getUserObject() instanceof SlimAvailableRadio) {
                SlimAvailableRadio radio = (SlimAvailableRadio) ((DefaultMutableTreeNode) value).getUserObject();
                setIcon(radio.getSmallIcon());
                setText(radio.getName());
            } else if (((DefaultMutableTreeNode) value).getUserObject() instanceof SlimRadioItem) {
                SlimRadioItem radio = (SlimRadioItem) ((DefaultMutableTreeNode) value).getUserObject();
                setIcon(radio.getSmallIcon());
                setText(radio.getName());
            }

            return this;
        }
    }

    public static void main(String[] args) {
        try {

            ImageIcon icon = new ImageIcon(new URL("http://172.30.74.5:9000/plugins/cache/icons/picks.png"));
            JLabel lbl = new JLabel(icon);

            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(lbl);
            frame.setVisible(true);

        } catch (MalformedURLException ex) {
            Logger.getLogger(SlimAvailableRadio.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
